﻿using Common.Tools;
using Microsoft.Extensions.DependencyInjection;
using Order.Domain.DomainService;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace Order.Common.IocHelper
{
    public static class ServiceCollectionExtension
    {
        /// <summary>
        /// 用DI批量注入接口程序集中对应的实现类。
        /// <para>
        /// 需要注意的是，这里有如下约定：
        /// IUserService --> UserService, IUserRepository --> UserRepository.
        /// </para>
        /// </summary>
        /// <param name="services"></param>
        /// <param name="assemblies">接口程序集</param>
        /// <returns></returns>
        public static void RegisterAssembly(this IServiceCollection services, Assembly[] assemblies)
        {       
            if (!assemblies.Any())
            {
                throw new DllNotFoundException($"程序集不存在！");
            }

            var types = RuntimeHelper.GetAllTypes(assemblies);

            var typeInterfaces = types.Where(t => t.GetTypeInfo().IsInterface);

            foreach (var type in typeInterfaces)
            {
                var implementTypeName = type.Name.Substring(1);
                var implementType = RuntimeHelper.GetImplementType(types, implementTypeName, type);
                if (implementType != null)
                    services.AddScoped(type, implementType);
            }
        }

        /// <summary>
        /// 用DI批量注入接口程序集中对应的实现类。
        /// </summary>
        /// <param name="services"></param>
        /// <param name="interfaceAssemblyName">接口程序集的名称（不包含文件扩展名）</param>
        /// <param name="implementAssemblyName">实现程序集的名称（不包含文件扩展名）</param>
        /// <returns></returns>
        public static void RegisterAssembly(this IServiceCollection services, string interfaceAssemblyName, string implementAssemblyName)
        {
            if (services == null)
                throw new ArgumentNullException(nameof(services));
            if (string.IsNullOrEmpty(interfaceAssemblyName))
                throw new ArgumentNullException(nameof(interfaceAssemblyName));
            if (string.IsNullOrEmpty(implementAssemblyName))
                throw new ArgumentNullException(nameof(implementAssemblyName));

            var interfaceAssembly = RuntimeHelper.GetAssembly(interfaceAssemblyName);
            if (interfaceAssembly == null)
            {
                throw new DllNotFoundException($"the dll \"{interfaceAssemblyName}\" not be found");
            }

            var implementAssembly = RuntimeHelper.GetAssembly(implementAssemblyName);
            if (implementAssembly == null)
            {
                throw new DllNotFoundException($"the dll \"{implementAssemblyName}\" not be found");
            }

            //过滤掉非接口及泛型接口
            //var types = interfaceAssembly.GetTypes().Where(t => t.GetTypeInfo().IsInterface && !t.GetTypeInfo().IsGenericType);
            //过滤掉非接口
            var types = interfaceAssembly.GetTypes().Where(t => t.GetTypeInfo().IsInterface);

            foreach (var type in types)
            {
                //过滤掉抽象类以及非class
                var implementType = implementAssembly.DefinedTypes
                    .FirstOrDefault(t => t.IsClass && !t.IsAbstract &&
                                         t.GetInterfaces().Any(b => b.Name == type.Name));
                if (implementType != null)
                {               
                    if (!type.Name.Contains("IBaseRepository"))
                    {
                        services.AddScoped(type, implementType.AsType());
                    }

                }
            }
        }

        /// <summary>
        /// 注册领域服务
        /// </summary>
        /// <param name="services"></param>
        /// <param name="assemblyName"></param>
        /// <returns></returns>
        public static void RegisterDomainServiceAssembly(this IServiceCollection services, Assembly[] assemblies)
        {
            if (!assemblies.Any())
            {
                throw new DllNotFoundException($"程序集不存在！");
            }
            var types = RuntimeHelper.GetAllTypes(assemblies).Where(t => t.GetTypeInfo().IsClass && typeof(IDomainService).IsAssignableFrom(t.GetTypeInfo()));

            foreach (var type in types)
            {
                services.AddScoped(type);
            }
        }

    }
}
